// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Alpha_shape_2.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Alpha_shapes_2/Py_Alpha_shape_2.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================

// Includes ====================================================================
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>

#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Alpha_shape_2.h>

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>

#include "Py_Alpha_shape_2_doc.h"

// Boost Includes ==============================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>

// Using =======================================================================
using namespace boost::python;

// Declarations ================================================================
namespace  {

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_mode_overloads_0_1, set_mode, 0, 1)

}// namespace 

template < class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha_shape_vertices(Alpha_shape_2& as)
{
	std::pair< iterator , iterator > p( as.alpha_shape_vertices_begin(), as.Alpha_shape_vertices_end() );
	return simple_python_iterator<iterator>(p);
}
template < class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha_shape_edges(Alpha_shape_2& as)
{
	std::pair< iterator , iterator > p( as.alpha_shape_edges_begin(), as.alpha_shape_edges_end() );
	return simple_python_iterator<iterator>(p);
}

template < class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha(Alpha_shape_2& as)
{
	std::pair< iterator , iterator > p( as.alpha_begin(), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}

//==================
template <class kernel,class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha_lower_bound(const Alpha_shape_2& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_lower_bound(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//=================
//==================
template <class kernel,class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha_upper_bound(const Alpha_shape_2& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_upper_bound(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//=================
//==================
template <class kernel,class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_alpha_find(const Alpha_shape_2& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_find(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//=================
//==================
template <class iterator,class Alpha_shape_2>
simple_python_iterator<iterator> py_find_optimal_alpha(Alpha_shape_2& as,int nb_components)
{
	std::pair< iterator , iterator > p( as.find_optimal_alpha(nb_components), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//==================
template <class kernel,class Alpha_shape_2>
int py_make_alpha_shape(Alpha_shape_2& as,const boost::python::list& points)
{
	typedef CGAL::Point_2<kernel> Point_2;
	std::list<Point_2> pts;
	int Nb = boost::python::extract<int>(points.attr("__len__")());
	for (int i = 0; i < Nb ; i++) pts.push_back(boost::python::extract<Point_2>(points[i]));
	return as.make_alpha_shape(pts.begin(),pts.end());
}

//================
//==================
template <class Alpha_shape_2 ,class class_name,class FT>
typename Alpha_shape_2::Classification_type py_classify(const Alpha_shape_2& as,const class_name& cl, const double& alpha)
{
	return as.classify(cl,FT(alpha));
}
//==================
template <class Alpha_shape_2 ,class class_name,class FT>
typename Alpha_shape_2::Classification_type py_classify_2(const Alpha_shape_2& as,const class_name& cl,int i, const double& alpha)
{
	return as.classify(cl,i,FT(alpha));
}
//==================
template <class Alpha_shape_2 ,class FT>
void py_set_alpha(Alpha_shape_2& as, const double& alpha)
{
	as.set_alpha(FT(alpha));
}
// Module ======================================================================
template <class kernel>
void Py_Alpha_shape_2()
{
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge, say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Delaunay_triangulation_2<kernel,Tds> 		Delaunay_triangulation_2;
	typedef CGAL::Alpha_shape_2<Delaunay_triangulation_2> 	Alpha_shape_2;

	typedef typename Alpha_shape_2::Classification_type 	Classification_type;
	typedef typename Alpha_shape_2::Mode 					Mode;
	typedef typename Alpha_shape_2::Face_handle 			Face_handle;
	typedef typename Alpha_shape_2::Vertex_handle 			Vertex_handle;
	typedef typename Alpha_shape_2::Alpha_shape_vertices_iterator 			Alpha_shape_vertices_iterator;
	typedef typename Alpha_shape_2::Alpha_shape_edges_iterator 				Alpha_shape_edges_iterator;
	typedef typename Alpha_shape_2::Alpha_iterator 				Alpha_iterator;

	typedef typename Alpha_shape_2::Edge 					Edge;
	typedef CGAL::Point_2<kernel> 							Point_2;
	typedef typename kernel::FT  FT;

    scope* Alpha_shape_2_scope = new scope(
    class_< Alpha_shape_2, bases< Delaunay_triangulation_2 > , boost::noncopyable >("Alpha_shape_2", Alpha_shape_2_doc,init< optional< double, Mode > >())
        .def("make_alpha_shape", &py_make_alpha_shape<kernel,Alpha_shape_2>,make_alpha_shape_doc)
        .def("clear", &Alpha_shape_2::clear,clear_doc)
        .def("set_alpha", &py_set_alpha<Alpha_shape_2,FT>,set_alpha_doc)
        .def("get_alpha", &Alpha_shape_2::get_alpha, return_value_policy< copy_const_reference >(),get_alpha_doc)
        .def("get_nth_alpha", &Alpha_shape_2::get_nth_alpha, return_value_policy< copy_const_reference >(),get_nth_alpha_doc)
        .def("number_of_alphas", &Alpha_shape_2::number_of_alphas,number_of_alphas_doc)
        .def("set_mode", &Alpha_shape_2::set_mode, set_mode_overloads_0_1(set_mode_doc))
        .def("get_mode", &Alpha_shape_2::get_mode,get_mode_doc)
        .def("alpha_find", &py_alpha_find<kernel,Alpha_iterator,Alpha_shape_2>,alpha_find_doc)
        .def("alpha_lower_bound", &py_alpha_lower_bound<kernel,Alpha_iterator,Alpha_shape_2>,alpha_lower_bound_doc)
        .def("alpha_upper_bound", &py_alpha_upper_bound<kernel,Alpha_iterator,Alpha_shape_2>,alpha_upper_bound_doc)

        .def("classify", (Classification_type (Alpha_shape_2::*)(const Point_2&) const)&Alpha_shape_2::classify)

        .def("classify", &py_classify<Alpha_shape_2,Point_2,FT>,classify_doc)

        .def("classify", (Classification_type (Alpha_shape_2::*)(const Face_handle&) const)&Alpha_shape_2::classify)

        .def("classify", &py_classify<Alpha_shape_2,Face_handle,FT>)

        .def("classify", (Classification_type (Alpha_shape_2::*)(const Edge&) const)&Alpha_shape_2::classify)

        .def("classify", (Classification_type (Alpha_shape_2::*)(const Face_handle&, int) const)&Alpha_shape_2::classify)

        .def("classify", &py_classify<Alpha_shape_2,Edge,FT>)

        .def("classify", &py_classify_2<Alpha_shape_2,Face_handle,FT>)

        .def("classify", (Classification_type (Alpha_shape_2::*)(const Vertex_handle&) const)&Alpha_shape_2::classify)

        .def("classify", &py_classify<Alpha_shape_2,Vertex_handle,FT>)

//        .def("number_solid_components", (int (Alpha_shape_2::*)() const)&Alpha_shape_2::number_solid_components,number_solid_components_doc)
//        .def("number_solid_components", (int (Alpha_shape_2::*)(const FT&) const)&Alpha_shape_2::number_solid_components,number_solid_components_doc)
        .def("number_of_solid_components", (int (Alpha_shape_2::*)() const)&Alpha_shape_2::number_of_solid_components,number_of_solid_components_doc)
        .def("number_of_solid_components", (int (Alpha_shape_2::*)(const FT&) const)&Alpha_shape_2::number_of_solid_components)
        .def("find_optimal_alpha", &py_find_optimal_alpha<Alpha_iterator,Alpha_shape_2>,find_optimal_alpha_doc)
		.add_property("alpha_shape_vertices",py_alpha_shape_vertices<Alpha_shape_vertices_iterator,Alpha_shape_2>)
 		.add_property("alpha_shape_edges",py_alpha_shape_edges<Alpha_shape_edges_iterator,Alpha_shape_2>)
 		.add_property("alpha",py_alpha<Alpha_iterator,Alpha_shape_2>)

   );

    enum_< Classification_type >("Classification_type")
        .value("INTERIOR", Alpha_shape_2::INTERIOR)
        .value("REGULAR", Alpha_shape_2::REGULAR)
        .value("EXTERIOR", Alpha_shape_2::EXTERIOR)
        .value("SINGULAR", Alpha_shape_2::SINGULAR)
    ;


    enum_< Mode >("Mode")
        .value("REGULARIZED", Alpha_shape_2::REGULARIZED)
        .value("GENERAL", Alpha_shape_2::GENERAL)
    ;

    delete Alpha_shape_2_scope;

	simple_python_iterator<Alpha_shape_vertices_iterator>::declare("Alpha_shape_vertices_iterator");
	simple_python_iterator<Alpha_shape_edges_iterator>::declare("Alpha_shape_edges_iterator");
	simple_python_iterator<Alpha_iterator>::declare("Alpha_iterator","Is an iterator that allow to traverse the increasing sequence of different alpha values.");

}

void export_Alpha_shape_2()
{
	Py_Alpha_shape_2<K>();
}
